﻿using System.Collections;
using System.Collections.Generic;
using NHDataAccess;
using NHibernate.Criterion;
using NHibernate.Type;

namespace NHDao
{
    public abstract class GenericNhibernateDao<T,Id> : IGenericDao<T,Id>
    {
        public T FindByid(Id id)
        {
            return NhibernateHelper.GetCurrentSession().Get<T>(id);
        }

        public IList<T> FindAll()
        {
            return NhibernateHelper.GetCurrentSession().CreateCriteria(typeof(T)).List<T>();
        }

        public IList<T> FindAllOrdered(IList<string> propertyNames)
        {
            var criteria = NhibernateHelper.GetCurrentSession().CreateCriteria(typeof(T));
            foreach (var propertyName in propertyNames)
            {
                criteria.AddOrder(Order.Asc(propertyName));
            }
            return criteria.List<T>();
        }

        public IList<T> FindByExample(T entity)
        {
            return NhibernateHelper.GetCurrentSession().CreateCriteria(typeof(T)).Add(Example.Create(entity)).List<T>();
        }

        public IList<T> FindBydExampleOrdered(T entity, IList<string> propertyNames)
        {
            var criteria = NhibernateHelper.GetCurrentSession().CreateCriteria(typeof(T)).Add(Example.Create(entity));
            foreach (var propertyName in propertyNames)
            {
                criteria.AddOrder(Order.Asc(propertyName));
            }
            return criteria.List<T>();
        }

        public IList<T> FindLikeExample(T entity)
        {
            return NhibernateHelper.GetCurrentSession().CreateCriteria(typeof(T)).Add(Example.Create(entity).EnableLike()).List<T>();
        }

        public IList<T> FindLikeExampleOrdered(T entity, IList<string> propertyNames)
        {
            var criteria = NhibernateHelper.GetCurrentSession().CreateCriteria(typeof(T)).Add(Example.Create(entity));
            foreach (var propertyName in propertyNames)
            {
                criteria.AddOrder(Order.Asc(propertyName));
            }
            return criteria.List<T>();
        }

        public IList<T> FindLikeExampleIgnoreCase(T entity)
        {
            return
                NhibernateHelper.GetCurrentSession().CreateCriteria(typeof(T)).Add(
                    Example.Create(entity).EnableLike().IgnoreCase()).List<T>();
        }

        public IList<T> FindLikeExampleIgnoreCaseOrdered(T entity, IList<string> propertyNames)
        {
            var criteria =
                NhibernateHelper.GetCurrentSession().CreateCriteria(typeof(T)).Add(
                    Example.Create(entity).EnableLike().IgnoreCase());
            foreach (var propertyName in propertyNames)
            {
                criteria.AddOrder(Order.Asc(propertyName));
            }
            return criteria.List<T>();
        }

        public IList<T> FindByQuery(string query)
        {
            return NhibernateHelper.GetCurrentSession().CreateQuery(query).List<T>();
        }

        public IList<T> FindByQuery(string myquery, string[] parameters, object[] values)
        {
            var query = NhibernateHelper.GetCurrentSession().CreateQuery(myquery);
            for (var i = 0; i < parameters.Length-1; i++)
            {
                query.SetParameter(parameters[i], values[i]);
            }
            return query.List<T>();
        }

        public IList<T> FindByNamedQuery(string query)
        {
            return NhibernateHelper.GetCurrentSession().GetNamedQuery(query).List<T>();
        }

        public IList<T> FindByNamedQuery(string myquery, string[] parameters, object[] values)
        {
            var query = NhibernateHelper.GetCurrentSession().GetNamedQuery(myquery);
            for (var i = 0; i < parameters.Length-1; i++)
            {
                query.SetParameter(parameters[i], values[i]);
            }
            return query.List<T>();
        }

        public System.Collections.IList FindObjectsByQuery(string query)
        {
            return NhibernateHelper.GetCurrentSession().CreateQuery(query).List();
        }

        public System.Collections.IList FindObjectsByNamedQuery(string query)
        {
            return NhibernateHelper.GetCurrentSession().GetNamedQuery(query).List();
        }

        public System.Collections.IList FindObjectsByNamedQuery(string myquery, string[] parameteres, object[] values)
        {
            var query = NhibernateHelper.GetCurrentSession().GetNamedQuery(myquery);
            for (var i = 0; i < parameteres.Length-1; i++)
            {
                query.SetParameter(parameteres[i], values[i]);
            }
            return query.List();
        }

        public IList FindObjectsBySQLQuery(string query)
        {
            return NhibernateHelper.GetCurrentSession().CreateSQLQuery(query).List();
        }

        public IList FindObjectsBySQLQuery(string myquery, string[] parameters, object[] values)
        {
            var query = NhibernateHelper.GetCurrentSession().CreateSQLQuery(myquery);
            for (int i = 0; i < parameters.Length-1; i++)
            {
                query.SetParameter(parameters[i], values[i]);
            }
            return query.List();
        }

        public T Save(T entity)
        {
            NhibernateHelper.GetCurrentSession().Save(entity);
            return entity;
        }

        public T Update(T entity)
        {
            NhibernateHelper.GetCurrentSession().Update(entity);
            return entity;
        }

        public void MakeTransient(T entity)
        {
            NhibernateHelper.GetCurrentSession().Delete(entity);
        }

        public Id GetMax(string propertyName)
        {
            return NhibernateHelper.GetCurrentSession().CreateCriteria(GetType()).SetProjection(Projections.ProjectionList().Add(Projections.Max(propertyName))).UniqueResult<Id>();
        }
        protected void DeleteObjectByQuery(string query, object[] values, IType[] types)
        {
            NhibernateHelper.GetCurrentSession().Delete(query, values, types);
        }
    }
}